/**
 * 
 */
package com.xbang.attendance.web.interceptor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.RequestUtils;
import org.apache.struts2.ServletActionContext;

import com.xbang.attendance.entity.role.Resource;
import com.xbang.attendance.entity.role.User;
import com.xbang.attendance.entity.system.Menu;
import com.xbang.attendance.security.support.SecurityUserHolder;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

/**
 * @author dev.zhang
 * @author Downpour
 * 
 */
public class AuthenticateInterceptor extends AbstractInterceptor {

	private static final long serialVersionUID = 6896292465476507396L;

	private static final Log logger = LogFactory.getLog(AuthenticateInterceptor.class);

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.opensymphony.xwork2.interceptor.AbstractInterceptor#intercept(com.opensymphony.xwork2.ActionInvocation)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public String intercept(ActionInvocation invocation) throws Exception {

		HttpServletRequest request = ServletActionContext.getRequest();
		String requestURI = getRequestURI(request);

		// returns all the menus and submenus
		List<Menu> menus = (List<Menu>) ServletActionContext.getServletContext().getAttribute("menus");
		Map<Integer, List<Menu>> submenus = (Map<Integer, List<Menu>>) ServletActionContext.getServletContext().getAttribute("submenus");

		// get current menu and submenu
		Menu menu = (Menu) invocation.getInvocationContext().getSession().get("menu");
		Menu submenu = (Menu) invocation.getInvocationContext().getSession().get("submenu");

		boolean isMenuClicked = false;

		// 1. collect menu information and determine currentMenu
		List<Menu> roleMenus = createRoleMenus(menus); // create role menus according to the role of user

		if (menu != null && !isCurrMenu(requestURI.split("/"), menu)) {
			// ///roleMenus
			menu = getCurrentMenu(roleMenus, submenu, requestURI);
		}

		if (menu == null) { // there is no current menu

			logger.info(">>>>>>>>>>>>>>>>>>>>> currenct url " + requestURI);
			// ///TODO.
			if (requestURI.contains("/")) {
				String menuCode = requestURI.split("/")[0];
				if (roleMenus != null && !roleMenus.isEmpty()) {
					for (Menu tmpMenu : roleMenus) {
						if (tmpMenu.getCode().equals(menuCode)) {
							menu = tmpMenu;
							break;
						}
					}
				}
			} else
				menu = roleMenus.get(0); // find the first role menu as the current menu
		} else {
			Menu entryMenu = determineEntryMenu(requestURI, roleMenus);
			if (entryMenu != null) { // to see if current menu needs to be changed
				menu = entryMenu;
				isMenuClicked = true;
			}
		}

		// 2. collect submenu information and determine currentSubmenu, all these depends on the currentMenu
		List<Menu> roleSubmenus = createRoleSubmenus(menu, submenus.get(menu.getId()));
		if (submenu == null || isMenuClicked) { // there is no current submenu
			submenu = roleSubmenus.get(0); // find the first role submenu as the current submenu
		} else {
			Menu entrySubmenu = determineEntrySubmenu(requestURI, roleSubmenus);
			if (entrySubmenu != null) { // to see if current submenu needs to be changed
				submenu = entrySubmenu;
			}
		}

		// 3. set for page view
		invocation.getInvocationContext().getSession().put("menu", menu);
		invocation.getInvocationContext().getSession().put("submenu", submenu);

		invocation.getInvocationContext().getSession().put("currentMenus", roleMenus);
		invocation.getInvocationContext().getSession().put("currentSubmenus", roleSubmenus);

		// put user session.
		User user = SecurityUserHolder.getCurrentUser();
		if (user != null) {
			invocation.getInvocationContext().getSession().put("user_", user);
		}
		// request.setAttribute("currentMenus", roleMenus);
		// request.setAttribute("currentSubmenus", roleSubmenus);

		return invocation.invoke();
	}

	/**
	 * 得到当前的Menu
	 * 
	 * @param roleMenus
	 * @param menu
	 * @param requestURI
	 * @return
	 */
	private Menu getCurrentMenu(List<Menu> roleMenus, Menu menu, String requestURI) {
		if (roleMenus == null || roleMenus.isEmpty()) {
			return null;
		}
		if (requestURI.indexOf("/") != -1) {
			String[] uris = requestURI.split("/");
			for (Menu tmpMenu : roleMenus) {
				if (isCurrMenu(uris, tmpMenu)) {
					return tmpMenu;
				}
			}
		} else {
			return menu;
		}

		return roleMenus.get(0);
	}

	private boolean isCurrMenu(String[] uris, Menu tmpMenu) {
		for (String string : uris) {
			if (tmpMenu.getCode().equals(string)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Create role menus according to the current thread local user
	 * 
	 * @param menus
	 * @return
	 */
	private List<Menu> createRoleMenus(List<Menu> menus) {
		List<Menu> roleMenus = new ArrayList<Menu>();
		List<Resource> menuResources = SecurityUserHolder.getCurrentMenuResources();
		for (Menu menu : menus) {
			for (Resource resource : menuResources) {
				if (menu.getCode().equals(resource.getValue())) {
					roleMenus.add(menu);
				}
			}
		}
		return roleMenus;
	}

	/**
	 * Create role submenus according to the current thread local user
	 * 
	 * @param menu
	 * @param submenus
	 * @return
	 */
	private List<Menu> createRoleSubmenus(Menu menu, List<Menu> submenus) {
		List<Menu> roleSubmenus = new ArrayList<Menu>();
		List<Resource> submenuResources = SecurityUserHolder.getCurrentSubmenuResources();
		for (Menu submenu : submenus) {
			for (Resource resource : submenuResources) {
				if (submenu.getCode().equals(resource.getValue())) {
					roleSubmenus.add(submenu);
				}
			}
		}
		return roleSubmenus;
	}

	/**
	 * Determine if the requestURI is the entry of the menu
	 * 
	 * @param requestURI
	 * @param menus
	 * @return
	 */
	protected Menu determineEntryMenu(String requestURI, List<Menu> menus) {
		for (Menu menu : menus) {
			if (requestURI.equals(menu.getUrl())) {
				return menu;
			}
		}
		return null;
	}

	/**
	 * 
	 * @param requestURI
	 * @param submenus
	 * @return
	 */
	protected Menu determineEntrySubmenu(String requestURI, List<Menu> submenus) {
		for (Menu submenu : submenus) {
			if (requestURI.equals(submenu.getUrl())) {
				return submenu;
			}
		}
		return null;
	}

	/**
	 * Gets the uri from the request
	 * 
	 * @param request
	 * @return
	 */
	protected String getRequestURI(final HttpServletRequest request) {
		// handle http dispatcher includes.
		String uri = (String) request.getAttribute("javax.servlet.include.servlet_path");
		if (uri != null) {
			return uri;
		}

		uri = RequestUtils.getServletPath(request);
		if (uri != null && !"".equals(uri)) {
			uri = uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri;
			return uri.substring(1);
		}

		uri = request.getRequestURI().substring(request.getContextPath().length());

		// remove the last '/' of requestURI to avoid some problems
		uri = uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri;

		return uri.substring(1); // remove the first '/'
	}

}
